home *** CD-ROM | disk | FTP | other *** search
- {
- This routine performs least squares curve fitting to arbitrary
- functions using the simplex method. This algorithm was derived
- from an article in the May 1984 issue of BYTE magazine written
- by Marco S. Caceci and William P. Cacheris, Florida State Univ.
- Refer to that article for an indepth discussion on the mech-
- anics of the program. Also see Nelder J.A. and R. Mead,
- Computer Jou. 7, 308 (1965) and L.A. Yarbro and S.N. Deming,
- Anal. Chim. Acta 74, 391 (1974).
-
- Writen for Turbo Pascal JUNE 1985
- by James G. Landowski 72167,2736
- Canoga Park, CA.
- }
-
- {
- Changed 2 to nvpp in several places.
- Corrected relative error to allow for negative values
-
- Lew Paper
- 9/27/85
- }
-
- const m = 2; { no. of parameters in equation to fit }
- nvpp = 2; { no. of variables per data point to solve for }
- n = 3; { points in simplex ( m + 1 ) }
- mnp = 200; { max. no. of data points that can be fit }
- alfa = 1.0; { reflection coeff. > 0 }
- beta = 0.5; { contraction coeff. 0 => 1 }
- gamma = 2.0; { expansion coeff. > 1 }
- root2 = 1.414214;
-
- type vector = array[1..n] of real;
- datavec = array[1..nvpp] of real;
- index = 0..255;
-
- var done :boolean;
- i,j :index;
- hi,lo :array[1..n] of index;
- np,
- maxiter,
- numiter : integer;
- next,
- center,
- mean,
- error,
- maxerr,
- p,q,
- step :vector;
- simp :array[1..n] of vector;
- data :array[1..mnp] of datavec;
- fname :string[14];
- din,
- dout :text;
- abs_max :REAL; {L.P.}
- { ----------------------------------------------------------------------}
- { Define the function to be fitted, 'C' is the coeff. vector,
- 'X' is the independent variable vector. This equation is the
- example used in the BYTE article.
- }
-
- function fnc(C:vector; X:datavec) :real;
- begin
- fnc := C[1] * X[1] /( C[2] + X[1] )
- end;
-
- { --------------------------------------------------------------------- }
- procedure sumresiduals (var s :vector);
-
- { computes the sum of squares of the residuals }
-
- var i:index;
-
- begin
- s[n] := 0.0;
- for i := 1 to np do { do for all data points }
- begin
- s[n] := s[n] + sqr( fnc(s,data[i])-data[i,nvpp] )
- end
- end;
-
- { ----------------------------------------------------------------------- }
- procedure inputdata;
-
- { gets all input data from a disk file. The filename is prompted for
- at runtime. An example of input data (from BYTE article) is:
-
- 100 maximum no. of iteration in search
- .2 3 starting coordinates of simplex
- .1 1 starting increments
- 1e-4 1e-4 1e-4 maximum error
- 1.68 .172 data ( 'mnp' is max. no. of entries )
- 3.33 .25 |
- 5.00 .286 |
- 6.67 .303 |
- 10.0 .334 |
- 20.0 .384 V
- }
-
- begin
- writeln(dout);
- writeln(dout,' Data file used for this run: ',fname);
- readln(din,maxiter);
- writeln(dout,' Maximum no. of iterations: ',maxiter:5);
-
- writeln(dout);
- writeln(dout,' Starting coordinates: ');
- write(dout,' ');
- for i := 1 to m do
- begin
- read(din,simp[1,i]);
- write(dout,simp[1,i],' ');
- end;
- writeln(dout);
- readln(din);
-
- writeln(dout);
- writeln(dout,' Starting steps:');
- write(dout,' ');
- for i := 1 to m do
- begin
- read(din,step[i]);
- write(dout,step[i],' ');
- end;
- writeln(dout);
- readln(din);
-
- writeln(dout);
- writeln(dout,' Maximum errors:');
- write(dout,' ');
- for i := 1 to n do
- begin
- read(din,maxerr[i]);
- write(dout,maxerr[i],' ');
- end;
- writeln(dout);
- readln(din);
-
- writeln(dout);
- writeln(dout,' Data:');
- np := 0;
- while NOT EOF(din) do
- begin
- np :=succ(np);
- write(dout,' #',np:2);
- for j := 1 to nvpp do
- begin
- read(din,data[np,j]);
- write(dout,data[np,j])
- end;
- readln(din);
- writeln(dout);
- end
- end;
- { ----------------------------------------------------------------------- }
-
- procedure outputdata;
-
- var y, dy, sigma :real;
- { pltout :text;}
-
- begin
-
- { Open output files for plot data when needed. }
-
- { assign(pltout,'SIMPLEX.PLT'); }
- { rewrite(pltout); }
-
- writeln(dout);
- writeln(dout,' Completion after ',numiter:5,' iterations');
- writeln(dout);
- writeln(dout,' Final Simplex:');
- for j := 1 to n do
- begin
- write(dout,' ');
- for i := 1 to n do
- write(dout,simp[j,i]:12,' ');
- writeln(dout);
- end;
- writeln(dout);
- writeln(dout,' Mean(s): ');
- for i := 1 to n do
- begin
- if i <> n then writeln(dout,' C',i:1,' ',mean[i]);
- if i = n then writeln(dout,' Residual: ',mean[i]);
- end;
- writeln(dout);
- writeln(dout,' Fractional Error:');
- write(dout,' ');
- for i := 1 to n do
- write(dout,error[i]);
- writeln(dout);
- writeln(dout);
- sigma := 0.0;
- for i := 1 to np do
- begin
- y := fnc(mean,data[i]);
- dy := data[i,nvpp]-y;
- sigma := sigma+sqr(dy);
- end;
- sigma := sqrt(sigma/np);
- writeln(dout,' Std. Dev. of error: ',sigma);
- sigma := sigma/sqrt(np-m);
- writeln(dout,' Estimate of error : ',sigma);
- writeln(dout);
- writeln(dout,' # x y y" dy');
- for i := 1 to np do
- begin
- y := fnc(mean,data[i]);
- dy := data[i,nvpp]-y;
- writeln(dout ,i:3,' ',data[i,1]:12,' ',data[i,nvpp]:12,' ',y:12,' ',
- dy:12);
- { writeln(pltout,i:3,' ',data[i,1]:12,' ',data[i,nvpp]:12,' ',y:12,' ',
- dy:12); }
- end;
- writeln(dout);
- writeln(dout,' -Done- ');
- end;
-
- { ----------------------------------------------------------------------- }
-
- procedure first;
- begin
- writeln(dout);
- writeln(dout,' Starting SIMPLEX');
- writeln(dout);
- for j := 1 to n do
- begin
- write(dout,' simp[',j:1,'] ');
- for i := 1 to n do
- write(dout,simp[j,i]:12,' ');
- writeln(dout)
- end;
- writeln(dout);
- end;
-
- { ----------------------------------------------------------------------- }
-
- procedure newvertex;
-
- begin
- { write(dout,' -> ',numiter:4); }
- for i := 1 to n do
- begin
- simp[hi[n],i] := next[i];
- { write(dout,next[i]) }
- end;
- { writeln(dout) }
- end;
-
- { ----------------------------------------------------------------------- }
-
- procedure order;
-
- var i,j :integer;
-
- begin
- for j := 1 to n do
- begin
- for i := 1 to n do
- begin
- if simp[i,j] < simp[lo[j],j] then lo[j] :=i;
- if simp[i,j] > simp[hi[j],j] then hi[j] :=i;
- end
- end
- end;
-
- { ----------------------------------------------------------------------- }
- { Main }
- begin
-
- write('Filename: ');
- readln(fname);
- assign(din,fname);
- reset(din);
- assign(dout,'simplex.out');
- rewrite(dout);
-
- inputdata;
-
- sumresiduals(simp[1]);
-
- for i := 1 to m do
- begin
- p[i] := step[i]*(sqrt(n)+m-1)/(m*root2);
- q[i] := step[i]*(sqrt(n)-1)/(m*root2)
- end;
- for i := 2 to n do
- begin
- for j := 1 to m do simp[i,j] := simp[1,j] + q[j];
- simp[i,i-1] := simp[1,i-1]+p[i-1];
- sumresiduals(simp[i])
- end;
- for i := 1 to n do
- begin
- lo[i] := 1;
- hi[i] := 1
- end;
-
- order;
- first;
- numiter := 0;
-
- repeat
- done := true;
- numiter := succ(numiter);
-
- for i := 1 to n do
- center[i] := 0.0;
- for i := 1 to n do
- if i<>hi[n] then
- for j := 1 to m do
- center[j] := center[j]+simp[i,j];
-
- for i := 1 to n do
- begin
- center[i] := center[i]/m;
- next[i] := (1.0+alfa)*center[i]-alfa*simp[hi[n],i];
- end;
- sumresiduals(next);
-
- if next[n] <= simp[lo[n],n] then
- begin
- newvertex;
- for i := 1 to m do
- next[i] := gamma*simp[hi[n],i]+(1.0-gamma)*center[i];
- sumresiduals(next);
- if next[n] <= simp[lo[n],n] then newvertex;
- end
- else
- begin
- if next[n] <= simp[hi[n],n] then
- newvertex
- else
- begin
- for i := 1 to m do
- next[i] := beta*simp[hi[n],i]+(1.0-beta)*center[i];
- sumresiduals(next);
- if next[n] <= simp[hi[n],n] then
- newvertex
- else
- begin
- for i := 1 to n do
- begin
- for j := 1 to m do
- simp[i,j] := (simp[i,j]+simp[lo[n],j])*beta;
- sumresiduals(simp[i]);
- end
- end
- end
- end;
- order;
- for j := 1 to n do
- begin
- IF ABS(simp[hi[j], j]) > ABS(simp[lo[j], j]) {L.P.}
- THEN {L.P.}
- abs_max := ABS(simp[hi[j], j]) {L.P.}
- ELSE {L.P.}
- abs_max := ABS(simp[lo[j], j]); {L.P.}
- error[j] :=
- (simp[hi[j],j]-simp[lo[j],j])/abs_max; {L.P.}
- if done then
- if error[j] > maxerr[j] then done := false;
- end;
-
- until (done or (numiter = maxiter));
-
- for i := 1 to n do
- begin
- mean[i] := 0.0;
- for j := 1 to n do
- mean[i] := mean[i]+simp[j,i];
- mean[i] := mean[i]/n;
- end;
- outputdata;
- close(dout);
- { close(pltout); }
- writeln;
- writeln('Done.... results in file "SIMPLEX.OUT"');
- end.
- $